#include "StdAfx.h"



SobelProcessor::SobelProcessor(void)
{
}


SobelProcessor::~SobelProcessor(void)
{
	//if( m_Image != NULL)
	//	cvReleaseImage(&m_Image);
}


SobelProcessor::SobelProcessor(IplImage* src,CString sImageName):m_Image(src),m_ImageName(sImageName)
{
}


pair<int,int> SobelProcessor::MarkPeaks(void)
{
	log4cplus::Logger logger =	log4cplus::Logger::getInstance("test.subtestof_filelog"); 
	vector<IplImage*> imgs(3,NULL);
	

	for (int i = 0; i < 3;i++)
	{
		imgs[i] = cvCreateImage(cvGetSize(m_Image),IPL_DEPTH_8U,1);
	}
	IplImage * pImage16uColorSobelProcessor = cvCreateImage(cvGetSize(m_Image),IPL_DEPTH_16S,1);
	//3 color channels
	cvCvtPixToPlane(m_Image,imgs[0],imgs[1],imgs[2],NULL);
	ROI roi;
	
	CString sExeFolder = roi.GetExeFolder();
	CString sFolder = sExeFolder + "\\Temp\\";
	if (GetFileAttributes(sFolder) == INVALID_FILE_ATTRIBUTES)
	{
		CreateDirectory(sFolder,NULL);
	}
	sFolder = sFolder + m_ImageName + "\\";

	if (GetFileAttributes(sFolder) == INVALID_FILE_ATTRIBUTES)
	{
		CreateDirectory(sFolder,NULL);
	}

	CString sChannelNames[3] = {"blue","green","red"};
	int firstPos = 0;
	int secondPos = 0;
	for(int i=0;i<3;i++)
	{
		cvSobel(imgs[i],pImage16uColorSobelProcessor,0,1,3);
		cvConvertScaleAbs(pImage16uColorSobelProcessor,imgs[i],1,0);
		CString s = "";
		s.Format("%s.png",sFolder+sChannelNames[i]);
		//cvSaveImage(s,imgs[i]);
		vector<int> counts = CountGrayScales(imgs[i]);
		
		//Dump2Txt(imgs[i], sFolder + sChannelNames[i] + ".txt");
		if( sChannelNames[i] == "blue") //blue channel
		{
			firstPos = MarkFirstPeak(counts);
			ofstream ofsTmp(sFolder + "First.txt");
			ofsTmp<<firstPos<<endl;
		}
		if( sChannelNames[i] == "red") //red channel
		{
			secondPos = MarkSecondPeak(counts,firstPos);
			ofstream ofsTmp(sFolder + "Second.txt");
			ofsTmp<<secondPos<<endl;
		}
	}

	
	LOG4CPLUS_INFO(logger,"hight level is :"<<firstPos<<", low level is: "<<secondPos);
		
	//3 channel to color image
	IplImage * colorful = cvCreateImage(cvGetSize(m_Image),IPL_DEPTH_8U,3);;
	cvCvtPlaneToPix(imgs[0],imgs[1],imgs[2],NULL,colorful);
	DrawMarkOnImage(firstPos,secondPos);
	CString sMarkedImage = sFolder+"marked.png";
	LOG4CPLUS_INFO(logger,"save path is :"<<sMarkedImage);

	cvSaveImage(sMarkedImage,m_Image);

	for(int i = 0; i< imgs.size(); i++)
		cvReleaseImage(&imgs[i]);
	cvReleaseImage(&pImage16uColorSobelProcessor);
	return make_pair(firstPos,secondPos);
}


void SobelProcessor::Dump2Txt(IplImage* img, CString sFile)
{
	int height = img->height;
	int width = img->width;
	uchar* pData=(uchar *)img->imageData;  
	int step = img->widthStep/sizeof(uchar);  
	int channels = img->nChannels;  
	int r, g, b;
	CvScalar avg = cvAvg(img);
	int intAvg = (avg.val[0] + avg.val[1] + avg.val[2])/3.0;
	
	//ofstream ofs(sFile) ;
	double kernelVal[9] = {-1,-0.5,0.5,1,2,1,0.5,-0.5,-1};
	vector<int> kernel;
	for( int i = 0; i< sizeof(kernelVal)/sizeof(double); i++)
	{
		kernel.push_back(kernelVal[i]);
	}
	vector<int> vals;
	for(int y = 0;y < height;y++)
	{
		b = g = r = 0;
		for(int x = 0;x< width;x++)
		{  
			b += pData[y*step+x*channels+0];  
			g += pData[y*step+x*channels+1];  
			r += pData[y*step+x*channels+2];  
		}  
		
		int avgThePixel = (b + g + r)/3.0;
		vals.push_back(avgThePixel);
		//ofs<<avgThePixel<<endl;
	}
	//vector<int> result = Convolve(vals,kernel);
	//sFile.Replace(".txt",".convolve");
	//ofstream ofs2(sFile);
	//for( int i = 0; i< result.size(); i++)
	//{
	//	ofs2<<result[i]<<endl;
	//}
}


vector<int> SobelProcessor::Convolve(vector<int>& signal, vector<int>& kernel)
{
	size_t n;
	size_t signalLen = signal.size();
	size_t kernalLen = kernel.size();
	vector<int> result(signalLen + kernalLen -1,0);
	
	for (n = 0; n < signalLen + kernalLen - 1; n++)
	{
		size_t kmin, kmax, k;

		result[n] = 0;

		kmin = (n >= kernalLen - 1) ? n - (kernalLen - 1) : 0;
		kmax = (n < signalLen - 1) ? n : signalLen - 1;

		for (k = kmin; k <= kmax; k++)
		{
			result[n] += signal[k] * kernel[n - k];
		}
	}

	return result;
}


int SobelProcessor::MarkFirstPeak(vector<int>& counts)
{
	vector<int>::iterator maxPos = max_element(counts.begin() ,counts.end());
	vector<int>::iterator itr = maxPos;
	//int total = accumulate(counts.begin(),counts.end(),0);
	//double avg = total/counts.size();
	
	for( ; itr != counts.end(); itr++)
	{
		if( (*itr) < (*maxPos/2))
		{
			break;
		}
	}
	return 1+distance(counts.begin(),itr);
}



int SobelProcessor::MarkSecondPeak(vector<int>& counts , int firstPos)
{
	int shift = 30;
	log4cplus::Logger logger =	log4cplus::Logger::getInstance("test.subtestof_filelog"); 
	
	if( firstPos + shift >= counts.size())
	{
		LOG4CPLUS_INFO(logger,"cannot find the second position, because the first is too near to the end.");
		return firstPos;
	}
	assert( firstPos + shift < counts.size());
	vector<int>::iterator maxPos = max_element(counts.begin() + shift+ firstPos - 1 ,counts.end());
	return 1+ distance(counts.begin(),maxPos);

}



vector<int> SobelProcessor::CountGrayScales(IplImage* img)
{
	int height = img->height;
	int width = img->width;
	uchar* pData=(uchar *)img->imageData;  
	int step = img->widthStep/sizeof(uchar);  
	int channels = img->nChannels;  
	int r, g, b;
	
		
	vector<int> vals;
	for(int y = 0;y < height;y++)
	{
		b = g = r = 0;
		for(int x = 0;x< width;x++)
		{  
			b += pData[y*step+x*channels+0];  
			g += pData[y*step+x*channels+1];  
			r += pData[y*step+x*channels+2];  
		}  
		
		int avgThePixel = (b + g + r)/3.0;
		vals.push_back(avgThePixel);
	}
	return vals;
}


void SobelProcessor::DrawMarkOnImage(int firstPeak, int secondPeak)
{
	int height = m_Image->height;
	int width = m_Image->width;
	uchar* pData=(uchar *)m_Image->imageData;  
	int step = m_Image->widthStep/sizeof(uchar);  
	int channels = m_Image->nChannels;  
	uchar r, g, b;

	//convert to 0 based index
	firstPeak--;
	secondPeak--;
	for(int y = 0;y < height;y++)
	{
		if( y != firstPeak && y != secondPeak )
			continue;
		if( y == firstPeak)
		{
			r = 255;
			g = b = 0;
		}
		else
		{
			g = 255;
			r = b = 0;
		}
		for(int x = 0;x< width;x++)
		{  
			pData[y*step+x*channels+0] = b;  
			pData[y*step+x*channels+1] = g;  
			pData[y*step+x*channels+2] = r;  
		}  
	}
}
